﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Xml.Serialization;
using System.Drawing.Drawing2D;

namespace VectorEditor
{
    public abstract class Primitive : ISerializable
    {
		public abstract RectangleF BoundingBox { get; }
        public Color BorderColor { get; set; }
        public float BorderWidth { get; set; }
        public abstract void Draw(Graphics g);
		
		public abstract bool HitTest(PointF pDoc);

        public Primitive()
        {
            BorderColor = Color.Black;
            BorderWidth = 1.0f;
        }

        #region ISerializable Members

        public virtual void Load(System.IO.BinaryReader reader)
        {
            BorderColor = Color.FromArgb(reader.ReadInt32());
            BorderWidth = reader.ReadSingle();
        }
        public virtual void Save(System.IO.BinaryWriter writer)
        {
            writer.Write(BorderColor.ToArgb());
            writer.Write(BorderWidth);
        }

        #endregion
		public virtual Primitive Clone()
		{
			var p = (Primitive)Activator.CreateInstance(this.GetType());
			p.BorderColor = BorderColor;
			p.BorderWidth = BorderWidth;
			return p;
		}
		public abstract void Transform(float dx, float dy, float scaleX, float scaleY);
	}

    public class LinePrimitive : Primitive
    {
        public PointF Point1 { get; set; }
        public PointF Point2 { get; set; }

		public override Primitive Clone()
		{
			var p = base.Clone() as LinePrimitive;
			p.Point1 = Point1;
			p.Point2 = Point2;
			return p;
		}

        public override void Draw(Graphics g)
        {
            g.DrawLine(new Pen(BorderColor, BorderWidth), Point1, Point2);
        }

        public override void Load(System.IO.BinaryReader reader)
        {
            base.Load(reader);
            Point1 = SerializationUtility.ReadPoint(reader);
            Point2 = SerializationUtility.ReadPoint(reader);
        }

        public override void Save(System.IO.BinaryWriter writer)
        {
            base.Save(writer);
            SerializationUtility.WritePoint(writer, Point1);
            SerializationUtility.WritePoint(writer, Point2);
        }

		public override bool HitTest(PointF pDoc)
		{
			throw new NotImplementedException();
		}

		public override RectangleF BoundingBox
		{
			get { return new RectangleF(Math.Min(Point1.X, Point2.X), Math.Min(Point1.Y, Point2.Y),
										Math.Abs(Point1.X - Point2.X), Math.Abs(Point1.Y - Point2.Y)); }
		}

		public override void Transform(float dx, float dy, float scaleX, float scaleY)
		{
			throw new NotImplementedException();
		}
	}
    public abstract class AreaPrimitive : Primitive
    {
        public float X { get; set; }
        public float Y { get; set; }
        public float Width { get; set; }
        public float Height { get; set; }

        public Color FillColor { get; set; }

        public AreaPrimitive()
        {
            FillColor = Color.Azure;
        }
		public override Primitive Clone()
		{
			var p = base.Clone() as AreaPrimitive;
			p.X = X;
			p.Y = Y;
			p.Width = Width;
			p.Height = Height;
			return p;
		}
        public override void Load(System.IO.BinaryReader reader)
        {
            base.Load(reader);
            X = reader.ReadSingle();
            Y = reader.ReadSingle();
            Width = reader.ReadSingle();
            Height = reader.ReadSingle();
            FillColor = Color.FromArgb(reader.ReadInt32());
        }

        public override void Save(System.IO.BinaryWriter writer)
        {
            base.Save(writer);
            writer.Write(X);
            writer.Write(Y);
            writer.Write(Width);
            writer.Write(Height);
            writer.Write(FillColor.ToArgb());
        }

		public override RectangleF BoundingBox
		{
			get { return new RectangleF(X, Y, Width, Height); }
		}

		public override void Draw(Graphics g)
		{
			throw new NotImplementedException();
		}

		public override bool HitTest(PointF pDoc)
		{
			throw new NotImplementedException();
		}

		public override void Transform(float dx, float dy, float scaleX, float scaleY)
		{
			X += dx;
			Y += dy;
			Width *= scaleX;
			Height *= scaleY;
		}
	}
    public class RectPrimitive : AreaPrimitive
    {

        public override void Draw(Graphics g)
        {
            g.FillRectangle(new SolidBrush(FillColor), X, Y, Width, Height);
            g.DrawRectangle(new Pen(BorderColor, BorderWidth), X, Y, Width, Height);
        }

		public override bool HitTest(PointF pDoc)
		{
			throw new NotImplementedException();
		}
	}
    public class EllipsePrimitive : AreaPrimitive
    {

        public override void Draw(Graphics g)
        {
            g.FillEllipse(new SolidBrush(FillColor), X, Y, Width, Height);
            g.DrawEllipse(new Pen(BorderColor, BorderWidth), X, Y, Width, Height);
        }

        public EllipsePrimitive()
        {
        }
        public EllipsePrimitive(float x, float y, float w, float h)
        {
            X = x;
            Y = y;
            Width = w;
            Height = h;
        }
        public EllipsePrimitive(RectangleF rect)
            : this(rect.X, rect.Y, rect.Width, rect.Height)
        {
        }

		public override bool HitTest(PointF pDoc)
		{
			float a = Width * 0.5f;
			float b = Height * 0.5f;
			float x = pDoc.X - (X + a);
			float y = pDoc.Y - (Y + b);

			float res = x * x / (a * a) + y * y / (b * b);
			if (res <= 1)
				return true;
			else
				return false;
		}
	}
}
